package com.sea.app.module.process.domain.service;

import com.sea.app.common.Entity.Page;
import com.sea.app.common.kit.Strings;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by 31417 on 2017/4/29.
 */
@Service
public class ActivitiProcessService {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    /**
     * 流程详情
     */
    private class ProcessDefinitionInfo{
        private ProcessDefinition processDefinition;
        private Deployment deployment;

        public ProcessDefinitionInfo(ProcessDefinition processDefinition, Deployment deployment) {
            this.processDefinition = processDefinition;
            this.deployment = deployment;
        }

        public ProcessDefinition getProcessDefinition() {
            return processDefinition;
        }

        public Deployment getDeployment() {
            return deployment;
        }
    }

    public ProcessInstance findInstance(String processInsId){
        return runtimeService.createProcessInstanceQuery().processInstanceId(processInsId).singleResult();
    }

    public Page<ProcessDefinitionInfo> list(Page<ProcessDefinitionInfo> page, String category) {

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .latestVersion().orderByProcessDefinitionKey().asc();
        if (!Strings.on(category).isBlank()){
            processDefinitionQuery.processDefinitionCategory(category);
        }

        page.setCount(processDefinitionQuery.count());
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(page.limitStart(), page.limitEnd());
        List<ProcessDefinitionInfo> processDefinitionInfos = new ArrayList<>(processDefinitionList.size());
        for (ProcessDefinition processDefinition : processDefinitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            processDefinitionInfos.add(new ProcessDefinitionInfo(processDefinition,deployment));
        }
        page.setList(processDefinitionInfos);
        return page;
    }

    /**
     * 获取由我开始的已完成的流程
     * @param userId
     * @return
     */
    public Page<HistoricProcessInstance> findProcessByUser(String userId, int start, int limit){
        long count = historyService.createHistoricProcessInstanceQuery().startedBy(userId).count();
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().startedBy(userId).finished().listPage(start,limit);
        return new Page<HistoricProcessInstance>(count,list);
    }

    /**
     * 获取由我开始且未完成的流程
     * @param userId
     * @return
     */
    public Page<HistoricProcessInstance> findUnfinishedProcessByUser(String userId, int start, int limit){
        long count = historyService.createHistoricProcessInstanceQuery().startedBy(userId).count();
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().startedBy(userId).unfinished().listPage(start,limit);
        return new Page<HistoricProcessInstance>(count,list);
    }

    /**
     * 获取流程列表
     * @param page
     * @param procInsId
     * @param procDefKey
     * @return
     */
    public Page<ProcessInstance> runningList(Page<ProcessInstance> page, String procInsId, String procDefKey) {

        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        if (!Strings.on(procInsId).isBlank()){
            processInstanceQuery.processInstanceId(procInsId);
        }
        if (!Strings.on(procDefKey).isBlank()){
            processInstanceQuery.processDefinitionKey(procDefKey);
        }
        page.setCount(processInstanceQuery.count());
        page.setList(processInstanceQuery.listPage(page.limitStart(), page.limitEnd()));
        return page;
    }





    private ProcessDefinition getProcessDefinitionById(String procDefId){
        return repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
    }
    private ProcessInstance getProcessInstanceById(String proInsId){
        return runtimeService.createProcessInstanceQuery().processInstanceId(proInsId).singleResult();
    }
    private InputStream getImageResourceByProcessDefinition(ProcessDefinition processDefinition){
        return repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
    }
    private InputStream getXMLResourceByProcessDefinition(ProcessDefinition processDefinition){
        return repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
    }

    /**
     * 获取流程实例图片
     * @param processInstanceId
     * @return
     */
    public InputStream processInstanceImage(String processInstanceId){
        ProcessDefinition processDefinition = getProcessDefinitionById(getProcessInstanceById(processInstanceId).getProcessDefinitionId());
        return getImageResourceByProcessDefinition(processDefinition);
    }

    /**
     * 获取流程实例XML
     * @param processInstanceId
     * @return
     */
    public InputStream processInstanceXML(String processInstanceId){
        ProcessDefinition processDefinition = getProcessDefinitionById(getProcessInstanceById(processInstanceId).getProcessDefinitionId());
        return getXMLResourceByProcessDefinition(processDefinition);
    }

    /**
     * 获取流程定义图片
     * @param procDefId
     * @return
     */
    public InputStream processDefinitionImage(String procDefId){
        return getImageResourceByProcessDefinition(getProcessDefinitionById(procDefId));
    }

    /**
     * 获取流程定义XML
     * @param procDefId
     * @return
     */
    public InputStream processDefinitionXML(String procDefId){
        return getXMLResourceByProcessDefinition(getProcessDefinitionById(procDefId));
    }

    /**
     *  开始流程
     * @param userId
     * @param processDefinitionId
     * @param businessKey
     * @param var
     * @return
     */
    public ProcessInstance startProcess(String userId, String processDefinitionId,String businessKey ,Map<String,Object> var) {
        Authentication.setAuthenticatedUserId(userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId,businessKey,var);
        return processInstance;
    }

    /**
     * 删除流程实例
     * @param procInsId
     * @param deleteReason
     */
    public void deleteProcessInstance(String procInsId, String deleteReason) {
        runtimeService.deleteProcessInstance(procInsId, deleteReason);
    }

}
